﻿using Dapper;
using Loong.Dapper;
using Loong.Dapper.DbAccessors;
using Loong.Dapper.Filters.Action;
using Loong.Dapper.Filters.Query;
using System;
using System.Threading.Tasks;

namespace Loong.BackgroundJobs
{
    public class BackgroundJobDbAccessor : DapperDbAccessorBase<BackgroundJobInfo, long>, IBackgroundJobDbAccessor
    {
        public BackgroundJobDbAccessor(
            IActiveTransactionProvider activeTransactionProvider,
            IDapperQueryFilterExecuter dapperQueryFilterExecuter,
            IDapperActionFilterExecuter dapperActionFilterExecuter)
            : base(activeTransactionProvider, dapperQueryFilterExecuter, dapperActionFilterExecuter)
        { }

        public async Task<BackgroundJobInfo> GetWaitingJobAsync()
        {
            string sql = @"
SELECT TOP 1
* 
FROM dbo.BackgroundJob
WHERE IsAbandoned=0
AND NextTryTime<=@now
AND (IsLocked=0 OR (IsLocked=1 AND LockEndTime<=@now))
ORDER BY [Priority] DESC,TryCount,NextTryTime
";
            return await Connection.QueryFirstOrDefaultAsync<BackgroundJobInfo>(sql, new { now = DateTime.Now }, Transaction);
        }

        public async Task<bool> LockJobAsync(BackgroundJobInfo jobInfo)
        {
            string sql = @"
UPDATE dbo.BackgroundJob SET
IsLocked=1,
LockEndTime=@LockEndTime
WHERE Id=@Id
";
            return (await Connection.ExecuteAsync(sql, new { jobInfo.Id, jobInfo.LockEndTime }, Transaction)) > 0;
        }

        public override async Task UpdateAsync(BackgroundJobInfo entity)
        {
            string sql = @"
SET NOCOUNT ON;
UPDATE [BackgroundJob] SET
[IsLocked] = @IsLocked,
[LockEndTime] = @LockEndTime,
[LastTryTime] = @LastTryTime,
[NextTryTime] = @NextTryTime,
[TryCount] = @TryCount,
[IsAbandoned] = @IsAbandoned
WHERE [Id] = @Id;
SELECT @@ROWCOUNT;
";
            await Connection.ExecuteAsync(sql, entity, Transaction);
        }
    }
}
